Skip to content

Conversation

@jmschonfeld
Copy link
Contributor

roundtripEncoding() is failing sporadically in CI due to how Calendars are encoded. When encoding/decoding a Calendar, if the encoded calendar is equal to Calendar.current at encode time, it will decode as whatever the Calendar.current is at decode time, even if different from the originally encoded calendar. This means that if the system is set to the GMT TimeZone (so this test's calendar is equal to Calendar.current) and another test changes the current calendar/locale between the encode call and the decode call, the decoded calendar (and recurrence rule) will compare inequality to the originally encoded value. Even though this is a FoundationEssentials test, this is possible because SwiftPM links and runs all test targets together into the same executable (unlike Xcode, where this issue does not reproduce as FoundationEssentials tests don't load FoundationInternationalization / don't parallelize with FoundationInternationalizationTests)

For now, until we can determine the long term expectation for this behavior, simply ensure that the current internationalization preferences can't be mutated while this test is running by moving it to the internationalization suite and using our helper function.

@jmschonfeld jmschonfeld force-pushed the roundtripEncoding-fix branch from 656b413 to 6c12ca6 Compare July 29, 2025 22:32
@jmschonfeld jmschonfeld changed the base branch from main to release/6.2 July 29, 2025 22:32
@jmschonfeld
Copy link
Contributor Author

@swift-ci please test

Copy link
Contributor

@itingliu itingliu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@parkera this is basically caused by this in Calendar.swift

     public func encode(to encoder: Encoder) throws {
...
        // current and autoupdatingCurrent are sentinel values. Calendar could theoretically not treat 'current' as a sentinel, but it is required for Locale (one of the properties of Calendar), so transitively we have to do the same here
        if self == Calendar.autoupdatingCurrent {
            try container.encode(Current.autoupdatingCurrent, forKey: .current)
        } else if self == Calendar.current {  // < --- encode as current here because they compare equal
            try container.encode(Current.current, forKey: .current)
        } else {
            try container.encode(Current.fixed, forKey: .current)
        }
    }

     public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        if let current = try container.decodeIfPresent(Current.self, forKey: .current) {
            switch current {
            case .autoupdatingCurrent:
                self = Calendar.autoupdatingCurrent
                return
            case .current:
                self = Calendar.current // <--- decode self as current here
                return
            case .fixed:
                // Fall through to identifier-based
                break
            }
        }

@parkera
Copy link
Contributor

parkera commented Jul 29, 2025

Yah, I think the encoding behavior is correct, so this change makes sense.

@jmschonfeld jmschonfeld merged commit a1c611f into swiftlang:release/6.2 Jul 30, 2025
16 checks passed
@jmschonfeld jmschonfeld deleted the roundtripEncoding-fix branch July 30, 2025 23:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants